package services

import (
	"fmt"
	"log"
	"math/rand"
	"strings"
	"time"

	"internal-net-bridge-server/internal/config"
	"internal-net-bridge-server/internal/models"

	"github.com/google/uuid"
	"gorm.io/gorm"
)

// TunnelService 隧道服务
type TunnelService struct {
	db         *gorm.DB
	dnsService *DNSPodService // DNSPod服务（可选）
}

// NewTunnelService 创建隧道服务实例
func NewTunnelService() *TunnelService {
	return &TunnelService{
		db:         config.DB,
		dnsService: nil, // DNSPod服务默认为空，需要手动设置
	}
}

// SetDNSService 设置DNSPod服务
func (s *TunnelService) SetDNSService(dnsService *DNSPodService) {
	s.dnsService = dnsService
	log.Printf("✅ TunnelService已关联DNSPod服务")
}

// CreateTunnelMapping 创建隧道映射
func (s *TunnelService) CreateTunnelMapping(userID uint, req *models.TunnelMappingRequest) (*models.TunnelMappingResponse, error) {
	// 生成唯一的隧道ID
	tunnelID := generateTunnelID()

	// 分配公网端口
	publicPort, err := s.allocatePublicPort()
	if err != nil {
		return nil, fmt.Errorf("分配公网端口失败: %w", err)
	}

	// 生成公网URL（初始）
	publicURL := s.generatePublicURL(tunnelID, req.TunnelType, publicPort, req.CustomDomain)

	// 🆕 如果启用了DNSPod服务，创建DNS记录
	var dnsRecord *DNSRecord
	httpFlag := req.TunnelType == models.TunnelTypeHTTP
	//todo 这里 s.dnsService为空了
	service := s.dnsService
	if service != nil && httpFlag {
		log.Printf("🌐 调用DNSPod创建DNS记录: 端口=%d", publicPort)

		record, err := service.CreateDNSRecord(int(publicPort))
		if err != nil {
			log.Printf("⚠️  DNSPod创建DNS记录失败: %v (将使用默认域名)", err)
			// 不影响主流程，继续使用默认域名
		} else {
			dnsRecord = record
			// 使用DNSPod生成的域名更新publicURL
			publicURL = fmt.Sprintf("https://%s", record.FullDomain)
			log.Printf("✅ DNS记录创建成功: %s -> %s:%d", record.FullDomain, service.publicIP, publicPort)
		}
	}

	// 创建隧道映射记录
	tunnelMapping := &models.TunnelMapping{
		TunnelID:      tunnelID,
		UserID:        userID,
		ServiceName:   req.ServiceName,
		LocalIP:       req.LocalIP,
		LocalPort:     req.LocalPort,
		PublicPort:    publicPort,
		CustomDomain:  req.CustomDomain,
		DNSProvider:   req.DNSProvider,
		TunnelType:    req.TunnelType,
		Status:        models.TunnelStatusConnecting,
		PublicURL:     &publicURL,
		TCPTunnelPort: req.TCPTunnelPort,
	}

	// 保存到数据库
	if err := s.db.Create(tunnelMapping).Error; err != nil {
		// 如果创建了DNS记录，需要清理
		if dnsRecord != nil {
			s.dnsService.DeleteDNSRecord(int(publicPort))
		}
		return nil, fmt.Errorf("保存隧道映射失败: %w", err)
	}

	// 异步更新状态为活跃
	go func() {
		time.Sleep(2 * time.Second) // 模拟连接建立时间
		s.UpdateTunnelStatus(tunnelID, models.TunnelStatusActive, nil)
	}()

	return tunnelMapping.ToResponse(), nil
}

// GetTunnelMappingByID 根据ID获取隧道映射
func (s *TunnelService) GetTunnelMappingByID(tunnelID string) (*models.TunnelMappingResponse, error) {
	// 如果数据库未连接，返回错误
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，无法查询隧道: %s", tunnelID)
		return nil, fmt.Errorf("数据库未连接")
	}

	var tunnelMapping models.TunnelMapping
	if err := s.db.Where("tunnel_id = ?", tunnelID).First(&tunnelMapping).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, fmt.Errorf("隧道不存在")
		}
		return nil, fmt.Errorf("查询隧道失败: %w", err)
	}

	return tunnelMapping.ToResponse(), nil
}

// GetTunnelMappingsByUserID 获取用户的所有隧道映射
func (s *TunnelService) GetTunnelMappingsByUserID(userID uint, page, size int) (*models.TunnelMappingListResponse, error) {
	// 如果数据库未连接，返回空列表
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，返回空隧道列表")
		return &models.TunnelMappingListResponse{
			Tunnels: []models.TunnelMappingResponse{},
			Count:   0,
			Page:    page,
			Size:    size,
			Total:   0,
		}, nil
	}

	var tunnelMappings []models.TunnelMapping
	var total int64

	// 查询总数
	if err := s.db.Model(&models.TunnelMapping{}).Where("user_id = ?", userID).Count(&total).Error; err != nil {
		return nil, fmt.Errorf("查询隧道总数失败: %w", err)
	}

	// 分页查询
	offset := (page - 1) * size
	if err := s.db.Where("user_id = ?", userID).
		Order("created_at DESC").
		Offset(offset).
		Limit(size).
		Find(&tunnelMappings).Error; err != nil {
		return nil, fmt.Errorf("查询隧道列表失败: %w", err)
	}

	// 转换为响应格式
	responses := make([]models.TunnelMappingResponse, len(tunnelMappings))
	for i, tunnel := range tunnelMappings {
		responses[i] = *tunnel.ToResponse()
	}

	return &models.TunnelMappingListResponse{
		Tunnels: responses,
		Count:   len(responses),
		Page:    page,
		Size:    size,
		Total:   total,
	}, nil
}

// GetAllActiveTunnelMappings 获取所有active状态的隧道映射（用于服务器启动时加载）
func (s *TunnelService) GetAllActiveTunnelMappings() ([]*models.TunnelMapping, error) {
	// 如果数据库未连接，返回空列表
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，返回空的active隧道列表")
		return []*models.TunnelMapping{}, nil
	}

	var tunnelMappings []*models.TunnelMapping

	if err := s.db.Where("status = ?", models.TunnelStatusActive).
		Order("created_at DESC").
		Find(&tunnelMappings).Error; err != nil {
		return nil, fmt.Errorf("查询active隧道失败: %w", err)
	}

	return tunnelMappings, nil
}

// GetAllTunnelMappingsByUserID 获取用户的所有隧道映射（不分页）
func (s *TunnelService) GetAllTunnelMappingsByUserID(userID uint) (*models.TunnelMappingListResponse, error) {
	// 如果数据库未连接，返回空列表
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，返回空隧道列表")
		return &models.TunnelMappingListResponse{
			Tunnels: []models.TunnelMappingResponse{},
			Count:   0,
		}, nil
	}

	var tunnelMappings []models.TunnelMapping

	if err := s.db.Where("user_id = ?", userID).
		Order("created_at DESC").
		Find(&tunnelMappings).Error; err != nil {
		return nil, fmt.Errorf("查询隧道列表失败: %w", err)
	}

	// 转换为响应格式
	responses := make([]models.TunnelMappingResponse, len(tunnelMappings))
	for i, tunnel := range tunnelMappings {
		responses[i] = *tunnel.ToResponse()
	}

	return &models.TunnelMappingListResponse{
		Tunnels: responses,
		Count:   len(responses),
	}, nil
}

// UpdateTunnelMapping 更新隧道映射
func (s *TunnelService) UpdateTunnelMapping(tunnelID string, userID uint, req *models.TunnelMappingRequest) (*models.TunnelMappingResponse, error) {
	// 如果数据库未连接，返回错误
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，无法更新隧道: %s", tunnelID)
		return nil, fmt.Errorf("数据库未连接")
	}

	var tunnelMapping models.TunnelMapping

	// 查找并验证所有权
	if err := s.db.Where("tunnel_id = ? AND user_id = ?", tunnelID, userID).First(&tunnelMapping).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, fmt.Errorf("隧道不存在或无权限访问")
		}
		return nil, fmt.Errorf("查询隧道失败: %w", err)
	}

	// 检查是否需要重新分配端口
	needNewPort := tunnelMapping.LocalPort != req.LocalPort || tunnelMapping.TunnelType != req.TunnelType
	oldPublicPort := tunnelMapping.PublicPort

	// 更新字段
	updates := map[string]interface{}{
		"service_name":    req.ServiceName,
		"local_ip":        req.LocalIP,
		"local_port":      req.LocalPort,
		"custom_domain":   req.CustomDomain,
		"dns_provider":    req.DNSProvider,
		"tunnel_type":     req.TunnelType,
		"tcp_tunnel_port": req.TCPTunnelPort,
		"updated_at":      time.Now(),
	}

	// 如果需要新端口，重新分配
	if needNewPort {
		newPublicPort, err := s.allocatePublicPort()
		if err != nil {
			return nil, fmt.Errorf("重新分配公网端口失败: %w", err)
		}
		updates["public_port"] = newPublicPort

		// 🆕 如果启用了DNSPod且旧端口有DNS记录，处理DNS更新
		var newPublicURL string
		if s.dnsService != nil && req.TunnelType == models.TunnelTypeHTTP {
			// 检查旧端口是否有DNS记录
			oldDomain, hasDNS := s.dnsService.GetDomainByPort(int(oldPublicPort))

			if hasDNS {
				// 域名已存在：删除旧DNS记录，创建新DNS记录
				log.Printf("🔄 域名已存在 %s，重新绑定到新端口 %d", oldDomain, newPublicPort)

				// 删除旧DNS记录
				if err := s.dnsService.DeleteDNSRecord(int(oldPublicPort)); err != nil {
					log.Printf("⚠️  删除旧DNS记录失败: %v", err)
				}

				// 创建新DNS记录
				record, err := s.dnsService.CreateDNSRecord(int(newPublicPort))
				if err != nil {
					log.Printf("⚠️  创建新DNS记录失败: %v (使用默认域名)", err)
					newPublicURL = s.generatePublicURL(tunnelID, req.TunnelType, newPublicPort, req.CustomDomain)
				} else {
					newPublicURL = fmt.Sprintf("https://%s", record.FullDomain)
					log.Printf("✅ DNS记录重新绑定: %s -> :%d", record.FullDomain, newPublicPort)
				}
			} else {
				// 域名不存在：创建新DNS记录
				record, err := s.dnsService.CreateDNSRecord(int(newPublicPort))
				if err != nil {
					log.Printf("⚠️  创建DNS记录失败: %v (使用默认域名)", err)
					newPublicURL = s.generatePublicURL(tunnelID, req.TunnelType, newPublicPort, req.CustomDomain)
				} else {
					newPublicURL = fmt.Sprintf("https://%s", record.FullDomain)
					log.Printf("✅ DNS记录创建成功: %s -> :%d", record.FullDomain, newPublicPort)
				}
			}
		} else {
			// 没有启用DNSPod，使用默认域名生成
			newPublicURL = s.generatePublicURL(tunnelID, req.TunnelType, newPublicPort, req.CustomDomain)
		}

		updates["public_url"] = newPublicURL
		// 更新状态为重新连接中
		updates["status"] = models.TunnelStatusConnecting
	}

	// 执行更新
	if err := s.db.Model(&tunnelMapping).Updates(updates).Error; err != nil {
		return nil, fmt.Errorf("更新隧道映射失败: %w", err)
	}

	// 如果需要新端口，异步更新状态
	if needNewPort {
		go func() {
			time.Sleep(2 * time.Second)
			s.UpdateTunnelStatus(tunnelID, models.TunnelStatusActive, nil)
		}()
	}

	// 重新查询返回最新数据
	if err := s.db.Where("tunnel_id = ?", tunnelID).First(&tunnelMapping).Error; err != nil {
		return nil, fmt.Errorf("查询更新后的隧道失败: %w", err)
	}

	return tunnelMapping.ToResponse(), nil
}

// DeleteTunnelMapping 删除隧道映射
func (s *TunnelService) DeleteTunnelMapping(tunnelID string, userID uint) error {
	// 如果数据库未连接，返回错误
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，无法删除隧道: %s", tunnelID)
		return fmt.Errorf("数据库未连接")
	}

	// 先查询隧道信息，用于清理DNS记录
	var tunnelMapping models.TunnelMapping
	if err := s.db.Where("tunnel_id = ? AND user_id = ?", tunnelID, userID).First(&tunnelMapping).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return fmt.Errorf("隧道不存在或无权限删除")
		}
		return fmt.Errorf("查询隧道失败: %w", err)
	}

	// 🆕 如果启用了DNSPod，清理DNS记录
	if s.dnsService != nil && tunnelMapping.PublicPort > 0 {
		publicPort := int(tunnelMapping.PublicPort)

		// 检查是否有DNS记录
		domain, hasDNS := s.dnsService.GetDomainByPort(publicPort)
		if hasDNS {
			log.Printf("🗑️  清理DNS记录: %s (端口: %d)", domain, publicPort)
			if err := s.dnsService.DeleteDNSRecord(publicPort); err != nil {
				log.Printf("⚠️  删除DNS记录失败: %v (继续删除隧道)", err)
				// 不影响隧道删除流程
			} else {
				log.Printf("✅ DNS记录已删除: %s", domain)
			}
		}
	}

	// 硬删除隧道映射（使用 Unscoped 真正删除数据库记录）
	result := s.db.Unscoped().Where("tunnel_id = ? AND user_id = ?", tunnelID, userID).Delete(&models.TunnelMapping{})

	if result.Error != nil {
		return fmt.Errorf("删除隧道映射失败: %w", result.Error)
	}

	if result.RowsAffected == 0 {
		return fmt.Errorf("隧道不存在或无权限删除")
	}

	log.Printf("✅ 隧道映射已硬删除（永久删除）: %s", tunnelID)
	return nil
}

// UpdateTunnelStatus 更新隧道状态
func (s *TunnelService) UpdateTunnelStatus(tunnelID, status string, errorMessage *string) error {
	// 如果数据库未连接，跳过状态更新
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，跳过更新隧道状态: %s", tunnelID)
		return nil
	}

	updates := map[string]interface{}{
		"status":     status,
		"updated_at": time.Now(),
	}

	if errorMessage != nil {
		updates["error_message"] = *errorMessage
	}

	if err := s.db.Model(&models.TunnelMapping{}).
		Where("tunnel_id = ?", tunnelID).
		Updates(updates).Error; err != nil {
		return fmt.Errorf("更新隧道状态失败: %w", err)
	}

	return nil
}

// UpdateTunnelStatusByUserID 更新指定用户的隧道状态（验证所有权）
func (s *TunnelService) UpdateTunnelStatusByUserID(tunnelID string, userID uint, status string, errorMessage *string) error {
	// 如果数据库未连接，跳过状态更新
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，跳过更新隧道状态: %s", tunnelID)
		return nil
	}

	updates := map[string]interface{}{
		"status":     status,
		"updated_at": time.Now(),
	}

	if errorMessage != nil {
		updates["error_message"] = *errorMessage
	} else {
		updates["error_message"] = nil
	}

	// 验证隧道所有权并更新状态
	result := s.db.Model(&models.TunnelMapping{}).
		Where("tunnel_id = ? AND user_id = ?", tunnelID, userID).
		Updates(updates)

	if result.Error != nil {
		return fmt.Errorf("更新隧道状态失败: %w", result.Error)
	}

	if result.RowsAffected == 0 {
		return fmt.Errorf("隧道不存在或无权限修改")
	}

	log.Printf("✅ 数据库状态更新成功: 隧道 %s -> %s", tunnelID, status)
	return nil
}

// GetTunnelMappingByPort 根据公网端口获取隧道映射
func (s *TunnelService) GetTunnelMappingByPort(publicPort int64) (*models.TunnelMappingResponse, error) {
	// 如果数据库未连接，返回 nil
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，无法查询隧道映射: port=%d", publicPort)
		return nil, fmt.Errorf("数据库未连接")
	}

	var tunnelMapping models.TunnelMapping
	if err := s.db.Where("public_port = ? AND status = ?", publicPort, models.TunnelStatusActive).
		First(&tunnelMapping).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, fmt.Errorf("未找到对应的隧道映射")
		}
		return nil, fmt.Errorf("查询隧道映射失败: %w", err)
	}

	return tunnelMapping.ToResponse(), nil
}

// GetTunnelMappingByServiceName 根据用户ID和服务名获取隧道映射
func (s *TunnelService) GetTunnelMappingByServiceName(userID uint, serviceName string) (*models.TunnelMappingResponse, error) {
	// 如果数据库未连接，返回 nil
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，无法查询隧道映射: service=%s", serviceName)
		return nil, nil
	}

	var tunnelMapping models.TunnelMapping
	if err := s.db.Where("user_id = ? AND service_name = ?", userID, serviceName).
		First(&tunnelMapping).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, fmt.Errorf("未找到对应的隧道映射")
		}
		return nil, fmt.Errorf("查询隧道映射失败: %w", err)
	}

	return tunnelMapping.ToResponse(), nil
}

// GetTunnelMappingByLocalAddress 根据本地地址(IP+端口)获取隧道映射（不验证用户）
func (s *TunnelService) GetTunnelMappingByLocalAddress(localIP string, localPort int64) (*models.TunnelMappingResponse, error) {
	// 如果数据库未连接，返回 nil（表示未找到）
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，无法查询隧道映射: %s:%d", localIP, localPort)
		return nil, nil
	}

	var tunnelMapping models.TunnelMapping
	if err := s.db.Where("local_ip = ? AND local_port = ?", localIP, localPort).
		First(&tunnelMapping).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil // 返回 nil 表示未找到，不是错误
		}
		return nil, fmt.Errorf("查询隧道映射失败: %w", err)
	}

	return tunnelMapping.ToResponse(), nil
}

// GetTunnelMappingByUserAndLocalAddress 根据用户ID和本地地址(IP+端口)获取隧道映射
func (s *TunnelService) GetTunnelMappingByUserAndLocalAddress(userID uint, localIP string, localPort int64) (*models.TunnelMappingResponse, error) {
	// 如果数据库未连接，返回 nil（表示未找到）
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，无法查询隧道映射: %s:%d", localIP, localPort)
		return nil, nil
	}

	var tunnelMapping models.TunnelMapping
	if err := s.db.Where("user_id = ? AND local_ip = ? AND local_port = ?", userID, localIP, localPort).
		First(&tunnelMapping).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil // 返回 nil 表示未找到，不是错误
		}
		return nil, fmt.Errorf("查询隧道映射失败: %w", err)
	}

	return tunnelMapping.ToResponse(), nil
}

// 私有方法

// generateTunnelID 生成唯一的隧道ID
func generateTunnelID() string {
	return uuid.New().String()
}

// allocatePublicPort 分配可用的公网端口
func (s *TunnelService) allocatePublicPort() (int64, error) {
	// 如果数据库未连接，使用随机端口（无冲突检测）
	if s.db == nil {
		const minPort = 10000
		const maxPort = 65535
		port := int64(rand.Intn(maxPort-minPort+1) + minPort)
		log.Printf("⚠️ 数据库未连接，分配随机端口（不检测冲突）: %d", port)
		return port, nil
	}

	// 端口范围: 10000-65535
	const minPort = 10000
	const maxPort = 65535

	// 最多尝试100次
	for i := 0; i < 100; i++ {
		port := int64(rand.Intn(maxPort-minPort+1) + minPort)

		// 检查端口是否已被使用
		var count int64
		if err := s.db.Model(&models.TunnelMapping{}).
			Where("public_port = ? AND status IN (?)", port, []string{models.TunnelStatusActive, models.TunnelStatusConnecting}).
			Count(&count).Error; err != nil {
			continue
		}

		if count == 0 {
			return port, nil
		}
	}

	return 0, fmt.Errorf("无法分配可用端口")
}

// generatePublicURL 生成公网访问URL
func (s *TunnelService) generatePublicURL(tunnelID, tunnelType string, publicPort int64, customDomain *string) string {
	if customDomain != nil && *customDomain != "" {
		if tunnelType == models.TunnelTypeHTTP {
			return fmt.Sprintf("https://%s", *customDomain)
		}
		return fmt.Sprintf("%s://%s:%d", tunnelType, *customDomain, publicPort)
	}

	// 生成随机子域名
	subdomain := generateRandomSubdomain()

	// 使用niuma946.com作为基础域名
	baseDomain := "niuma946.com"

	if tunnelType == models.TunnelTypeHTTP {
		return fmt.Sprintf("https://%s.%s", subdomain, baseDomain)
	}

	// 对于非HTTP类型，使用TCP端口访问
	return fmt.Sprintf("%s://%s.%s:%d", tunnelType, subdomain, baseDomain, publicPort)
}

// generateRandomSubdomain 生成随机子域名（8个字符，字母+数字）
func generateRandomSubdomain() string {
	const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
	const length = 8

	result := make([]byte, length)
	for i := range result {
		result[i] = charset[rand.Intn(len(charset))]
	}

	return string(result)
}

// UpdateTunnelPublicURL 更新隧道的公网URL
func (s *TunnelService) UpdateTunnelPublicURL(tunnelID, publicURL string) error {
	// 如果数据库未连接，跳过更新
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，跳过更新隧道公网URL: %s", tunnelID)
		return nil
	}

	result := s.db.Model(&models.TunnelMapping{}).
		Where("tunnel_id = ?", tunnelID).
		Update("public_url", publicURL)

	if result.Error != nil {
		return fmt.Errorf("更新隧道公网URL失败: %v", result.Error)
	}

	if result.RowsAffected == 0 {
		return fmt.Errorf("未找到隧道记录: %s", tunnelID)
	}

	log.Printf("✅ 更新隧道公网URL: %s -> %s", tunnelID, publicURL)
	return nil
}

// GetDomainByTunnelID 根据隧道ID获取域名
func (s *TunnelService) GetDomainByTunnelID(tunnelID string) (string, error) {
	// 如果数据库未连接，返回错误
	if s.db == nil {
		log.Printf("⚠️ 数据库未连接，无法查询隧道域名: %s", tunnelID)
		return "", fmt.Errorf("数据库未连接")
	}

	var tunnelMapping models.TunnelMapping
	if err := s.db.Where("tunnel_id = ?", tunnelID).First(&tunnelMapping).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return "", fmt.Errorf("隧道不存在")
		}
		return "", fmt.Errorf("查询隧道失败: %w", err)
	}

	if tunnelMapping.PublicURL == nil {
		return "", fmt.Errorf("隧道没有公网URL")
	}

	// 从URL中提取域名
	domain := extractDomainFromURL(*tunnelMapping.PublicURL)
	return domain, nil
}

// extractDomainFromURL 从URL中提取域名
func extractDomainFromURL(rawURL string) string {
	// 移除协议部分
	domain := rawURL
	if idx := strings.Index(domain, "://"); idx != -1 {
		domain = domain[idx+3:]
	}

	// 移除端口部分
	if idx := strings.Index(domain, ":"); idx != -1 {
		domain = domain[:idx]
	}

	// 移除路径部分
	if idx := strings.Index(domain, "/"); idx != -1 {
		domain = domain[:idx]
	}

	return domain
}

// init 初始化随机数种子
func init() {
	rand.Seed(time.Now().UnixNano())
}
